package com.vchecker.iobd_checker.utils;

/**
 * Created by Yipb on 16-3-14.
 */
public class Utils {
    // ************************************************************************************
    // 函数介绍：根据命令ID，长度低字节以及数据帧计算效验位数据
    // 数据校验（Check）的方式步骤如下：
    // 1. 将数据帧内容（Data Bytes）的所有数据相加，舍弃高位，得到一个字CSW（2个BYTE）。
    // 2. 将CSW与数据帧命令字（Command ID）进行异或，得到CSW2。
    // 3. 数据帧长度低字节（Lenth Byte2）与0x10取余的结果记作LN，将CSW2循环左移LN位得到CSW3。
    // 4. CSW3的高字节记作CSWH，低字节记作CSWL，CSWH与CSWL相加并舍弃高位得CS
    // 入口参数：wCmdID:命令ID
    // LenByte2:数据帧长度低字节
    // bData:数据帧
    // 出口参数：(无)
    // 返回值： (计算后的校验位
    // ************************************************************************************
    public static byte calcCheckBit(int wCmdID, int wLenByte2, byte[] pbData,
                                    int wDataLen) {
        byte FrameCs = 0, FrameCs_CSWH = 0, FrameCs_CSWL = 0;
        int FrameCs_CSW = 0, FrameCs_CSW2 = 0, FrameCs_LN = 0, FrameCs_CSW3 = 0, Frame_CommandID = 0;

        for (int i = 0; i < wDataLen; i++) {
            FrameCs_CSW = (int) (FrameCs_CSW + (pbData[i] & 0xff));
        }

        // 计算校验数据，判断是否正确
        Frame_CommandID = wCmdID; // RecvFrame->FrameData.Command_ID1*0x100 +
        // RecvFrame->FrameData.Command_ID2;
        FrameCs_CSW2 = (FrameCs_CSW ^ Frame_CommandID);
        FrameCs_LN = (wLenByte2 % 0x10); // RecvFrame->FrameData.Lenth_Byte2
        // 需要移动的数据a,长度N(8 16 32),移动的位数n
        // 循环左移:(a<<n)|(a>>(N-n))
        // 循环右移:(a>>n)|(a<<(N-n))
        FrameCs_CSW3 = ((FrameCs_CSW2 << FrameCs_LN) | (FrameCs_CSW2 >> (16 - FrameCs_LN)));
        FrameCs_CSWH = (byte) ((FrameCs_CSW3 & 0xff00) >> 8);
        FrameCs_CSWL = (byte) (FrameCs_CSW3 & 0x00ff);
        FrameCs = (byte) (FrameCs_CSWH + FrameCs_CSWL);

        return FrameCs;
    }

}
